/* 
 * Copyright [2018] [Alex/libo(liboms@hotmail.com)]
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hyts.guava.String;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

import com.google.common.base.CaseFormat;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.hyts.guava.config.StringConfig;
import com.hyts.guava.object.Objects;

/** 
 * @title Strings.java  
 * @package com.hyts.guava.String  
 * @description 此类主要负责实现支持Guava框架的String字符串操作方法<br>
 * 				 功能：<br>
 * 				1.连接器[Joiner) <br>
 * 			    2.拆分器（Splitter）<br>
 * 			    3.字符串匹配器(CharMatcher)<br>
 * 			    4.字符集（charset）<br>
 * 			    5.大小写格式(caseFormat)
 * @see com.google.common.base.Strings
 * @author libo/Alex
 * @email liboms@hotmail.com/liboware@163.com  
 * @date 2018年5月5日 
 * @version V1.0 
 */
public final class Strings {

	
	/**  
	 * <b>isEmpty:判断是否为空</b>
	 * <p>包含null以及长度为0的状态</p>
	 * @param param
	 * @return
	 * @exception
	 */ 
	public static boolean isEmpty(String param){
		return com.google.common.base.Strings.isNullOrEmpty(param);
	}
	
	/**  
	 * <b>isNull:判断是否为空</b>
	 * <p>包含null</p>
	 * @param param
	 * @return
	 * @exception
	 */ 
	public static boolean isNull(String param){
		return Objects.isNull(param);
	}
	
	/**  
	 * <b>isBlank:最强大的空判断</b>
	 * <p>包含 null,"null","NULL",""," "," null","null "等</p>
	 * @param param
	 * @return
	 * @exception
	 */ 
	public static boolean isBlank(String param){
	    return isEmpty(param) || 
	    		param.trim().length() == 0 ||
	    		"null".trim().equalsIgnoreCase(param);
	}

	/**  
	 * <b>isNotEmpty:判断是否为非空</b>
	 * <p>包含null以及长度为0的状态</p>
	 * @param param
	 * @return
	 * @exception
	 */ 
	public static boolean isNotEmpty(String param){
	    return !isEmpty(param);
	}
	
	/**  
	 * <b>isNotNull:判断是否为非空</b>
	 * <p>包含null</p>
	 * @param param
	 * @return
	 * @exception
	 */ 
	public static boolean isNotNull(String param){
	    return !isNull(param);
	}
	
	/**  
	 * <b>isNotBlank:最强大的非空判断</b>
	 * <p>包含 null,"null","NULL",""," "," null","null "等</p>
	 * @param param
	 * @return
	 * @exception
	 */ 
	public static boolean isNotBlank(String param){
	    return !isBlank(param);
	}
	
	/**  
	 * <b>compareNullAndSet</b>
	 * <p>比较为空 则采取得的默认值进行赋值</p>
	 * @return
	 * @exception
	 */ 
	public static String compareNullAndSet(String param,String defaultValue){
		return isNull(param)?defaultValue:param;
	}
	
	/**  
	 * <b>compareEmptyAndSet</b>
	 * <p>比较为空 则采取得的默认值进行赋值</p>
	 * @param param
	 * @param defaultValue
	 * @return
	 * @exception
	 */ 
	public static String compareEmptyAndSet(String param,String defaultValue){
		return isEmpty(param)?defaultValue:param;
	}
	
	/**  
	 * <b>compareBlankAndSet</b>
	 * <p>比较为空 则采取得的默认值进行赋值</p>
	 * @param param
	 * @param defaultValue
	 * @return
	 * @exception
	 */ 
	public static String compareBlankAndSet(String param,String defaultValue){
		return isBlank(param)?defaultValue:param;
	}
	
	/**  
	 * <b>join 拼接字符串</b>
	 * <p>拼接字符串:根据指定的标识符</p>
	 * @param param List,Array都可以
	 * @param joinToken 拼接的符号，默认为,
	 * @param isIgnoreNull 是否忽略空
	 * @return 拼接的字符串结果
	 * @exception NullPointerException
	 */ 
	@SuppressWarnings("unchecked")
	public static String join(Object param,String joinToken,boolean isIgnoreNull){
		//校验数组是否为空指针
		Objects.checkNull(param);
		//因为是值传递，所以引用的地址从传递
		Strings.compareBlankAndSet(joinToken,StringConfig.DEAFAULT_JOIN_TOKEN);
		//校验是否忽略空
		Joiner joiner = isIgnoreNull?Joiner.on(joinToken).skipNulls():Joiner.on(joinToken);
		//针对于多种类型进行操作
		if (param instanceof List){
			return joiner.join((List<String>)param);
		}else if (param instanceof Iterator){
			return joiner.join((Iterator)param);
		}else if (param.getClass().isArray()){
			return joiner.join((Object[])param);
		}
		return null;
	}
	 
	 /**  
	 * <b>join 拼接字符串</b>
	 * <p>拼接字符串:根据指定的标识符</p>
	 * @param param List,Array都可以
	 * @param joinToken 拼接的符号，默认为,
	 * @return 拼接的字符串结果
	 * @exception NullPointerException
	 */ 
	public static String join(Object param,String joinToken){
		//校验数组是否为空指针
		Objects.checkNull(param);
		//因为是值传递，所以引用的地址从传递
		Strings.compareBlankAndSet(joinToken,StringConfig.DEAFAULT_JOIN_TOKEN);
		//校验是否忽略空
		Joiner joiner = Joiner.on(joinToken);
		//针对于多种类型进行操作
		if (param instanceof List){
			return joiner.join((List<String>)param);
		}else if (param instanceof Iterator){
			return joiner.join((Iterator)param);
		}else if (param.getClass().isArray()){
			return joiner.join((Object[])param);
		}
		return null;
	}
	
	 /**  
	  * <b>join 拼接字符串</b>
	  * <p>拼接字符串:根据指定的标识符,替换null</p>
	  * @param param List,Array都可以
	  * @param joinToken 拼接的符号，默认为‘,’
	  * @param replaceNull 替换null
	  * @return 拼接的字符串结果
	  * @exception NullPointerException
	  */ 
	public static String join(Object param,String joinToken,String replaceNull){
		//校验数组是否为空指针
		Objects.checkNull(param);
		//因为是值传递，所以引用的地址从传递
		Strings.compareBlankAndSet(joinToken,StringConfig.DEAFAULT_JOIN_TOKEN);
		//校验是否忽略空
		Joiner joiner = Joiner.on(joinToken).useForNull(replaceNull);
		//针对于多种类型进行操作
		if (param instanceof List){
			return joiner.join((List<String>)param);
		}else if (param instanceof Iterator){
			return joiner.join((Iterator)param);
		}else if (param.getClass().isArray()){
			return joiner.join((Object[])param);
		}
		return null;
	}
	
	/**  
	 * <b>splitToList</b>
	 * JDK 内建的字符串拆分工具有一些古怪的特性。<br>
	        比如，String.split 悄悄丢弃了尾部的分隔符。 问<br>
	        题：”,a,,b,”.split(“,”)返回？<br>
	   1. “”, “a”, “”, “b”, “”<br>
	   2. null, “a”, null, “b”, null<br>
       3. “a”, null, “b”<br>
       4. “a”, “b”<br>
       5. 以上都不对<br>
     * @param param
	 * @param splitToken
	 * @param isIgnoreNull
	 * @return
	 * @exception
	 */ 
	public static List<String> splitToList(String param,String splitToken,boolean isIgnoreNull){
		Strings.compareNullAndSet(param, "");
		Strings.compareBlankAndSet(splitToken,StringConfig.DEAFAULT_SPLIT_TOKEN);
		Splitter splitter = isIgnoreNull?Splitter.on(splitToken).trimResults().omitEmptyStrings():
							Splitter.on(splitToken).trimResults().limit(StringConfig.MAX_LIMIET_SPLIT);
		return splitter.splitToList(param);
	}
	
	/**  
	 * <b>splitToIterator</b>
	 * JDK 内建的字符串拆分工具有一些古怪的特性。<br>
	        比如，String.split 悄悄丢弃了尾部的分隔符。 问<br>
	        题：”,a,,b,”.split(“,”)返回？<br>
	   1. “”, “a”, “”, “b”, “”<br>
	   2. null, “a”, null, “b”, null<br>
       3. “a”, null, “b”<br>
       4. “a”, “b”<br>
       5. 以上都不对<br>
     * @param param
	 * @param splitToken
	 * @param isIgnoreNull
	 * @return
	 * @exception
	 */
	public static Iterator<String> splitToIterator(String param,String splitToken,boolean isIgnoreNull){
		Strings.compareNullAndSet(param, "");
		Strings.compareBlankAndSet(splitToken,StringConfig.DEAFAULT_SPLIT_TOKEN);
		Splitter splitter = isIgnoreNull?Splitter.on(splitToken).trimResults().omitEmptyStrings():
							Splitter.on(splitToken).trimResults().limit(StringConfig.MAX_LIMIET_SPLIT);
		return splitter.split(param).iterator();
	}
	
	/**  
	 * <b>splitToList</b>
	 * JDK 内建的字符串拆分工具有一些古怪的特性。<br>
	        比如，String.split 悄悄丢弃了尾部的分隔符。 问<br>
	        题：”,a,,b,”.split(“,”)返回？<br>
	   1. “”, “a”, “”, “b”, “”<br>
	   2. null, “a”, null, “b”, null<br>
       3. “a”, null, “b”<br>
       4. “a”, “b”<br>
       5. 以上都不对<br>
     * @param param
	 * @param splitToken
	 * @param isIgnoreNull
	 * @return
	 * @exception
	 */ 
	public static List<String> splitToList(String param,String splitToken){
		Strings.compareNullAndSet(param, "");
		Strings.compareBlankAndSet(splitToken,StringConfig.DEAFAULT_SPLIT_TOKEN);
		Splitter splitter = Splitter.on(splitToken).trimResults().omitEmptyStrings().limit(StringConfig.MAX_LIMIET_SPLIT);
		return splitter.splitToList(param);
	}
	
	/**  
	 * <b>splitToIterator</b>
	 * JDK 内建的字符串拆分工具有一些古怪的特性。<br>
	        比如，String.split 悄悄丢弃了尾部的分隔符。 问<br>
	        题：”,a,,b,”.split(“,”)返回？<br>
	   1. “”, “a”, “”, “b”, “”<br>
	   2. null, “a”, null, “b”, null<br>
       3. “a”, null, “b”<br>
       4. “a”, “b”<br>
       5. 以上都不对<br>
     * @param param
	 * @param splitToken
	 * @param isIgnoreNull
	 * @return
	 * @exception
	 */
	public static Iterator<String> splitToIterator(String param,String splitToken){
		Strings.compareNullAndSet(param, "");
		Strings.compareBlankAndSet(splitToken,StringConfig.DEAFAULT_SPLIT_TOKEN);
		Splitter splitter = Splitter.on(splitToken).trimResults().omitEmptyStrings().limit(StringConfig.MAX_LIMIET_SPLIT);
		return splitter.split(param).iterator();
	}
	
	/**  
	 * <b>splitToList</b>
	 * JDK 内建的字符串拆分工具有一些古怪的特性。<br>
	        比如，String.split 悄悄丢弃了尾部的分隔符。 问<br>
	        题：”,a,,b,”.split(“,”)返回？<br>
	   1. “”, “a”, “”, “b”, “”<br>
	   2. null, “a”, null, “b”, null<br>
       3. “a”, null, “b”<br>
       4. “a”, “b”<br>
       5. 以上都不对<br>
     * @param param
	 * @param splitToken
	 * @param isIgnoreNull
	 * @return
	 * @exception
	 */ 
	public static List<String> splitToList(String param,String splitToken,int limited){
		Strings.compareNullAndSet(param, "");
		Strings.compareBlankAndSet(splitToken,StringConfig.DEAFAULT_SPLIT_TOKEN);
		Splitter splitter = Splitter.on(splitToken).trimResults().omitEmptyStrings().limit(limited);
		return splitter.splitToList(param);
	}
	
	/**  
	 * <b>splitToIterator</b>
	 * JDK 内建的字符串拆分工具有一些古怪的特性。<br>
	        比如，String.split 悄悄丢弃了尾部的分隔符。 问<br>
	        题：”,a,,b,”.split(“,”)返回？<br>
	   1. “”, “a”, “”, “b”, “”<br>
	   2. null, “a”, null, “b”, null<br>
       3. “a”, null, “b”<br>
       4. “a”, “b”<br>
       5. 以上都不对<br>
     * @param param
	 * @param splitToken
	 * @param isIgnoreNull
	 * @return
	 * @exception
	 */
	public static Iterator<String> splitToIterator(String param,String splitToken,int limited){
		Strings.compareNullAndSet(param, "");
		Strings.compareBlankAndSet(splitToken,StringConfig.DEAFAULT_SPLIT_TOKEN);
		Splitter splitter = Splitter.on(splitToken).trimResults().omitEmptyStrings().limit(limited);
		return splitter.split(param).iterator();
	}
	
	/**  
	 * <b>splitToList</b>
	 * JDK 内建的字符串拆分工具有一些古怪的特性。<br>
	        比如，String.split 悄悄丢弃了尾部的分隔符。 问<br>
	        题：”,a,,b,”.split(“,”)返回？<br>
	   1. “”, “a”, “”, “b”, “”<br>
	   2. null, “a”, null, “b”, null<br>
       3. “a”, null, “b”<br>
       4. “a”, “b”<br>
       5. 以上都不对<br>
     * @param param
	 * @param splitToken
	 * @param isIgnoreNull
	 * @return
	 * @exception
	 */ 
	public static List<String> splitToList(String param,String splitToken,boolean isIgnoreNull,int limited){
		Strings.compareNullAndSet(param, "");
		Strings.compareBlankAndSet(splitToken,StringConfig.DEAFAULT_SPLIT_TOKEN);
		Splitter splitter = isIgnoreNull?Splitter.on(splitToken).trimResults().omitEmptyStrings():
							Splitter.on(splitToken).trimResults().limit(limited);
		return splitter.splitToList(param);
	}
	
	/**  
	 * <b>splitToIterator</b>
	 * JDK 内建的字符串拆分工具有一些古怪的特性。<br>
	        比如，String.split 悄悄丢弃了尾部的分隔符。 问<br>
	        题：”,a,,b,”.split(“,”)返回？<br>
	   1. “”, “a”, “”, “b”, “”<br>
	   2. null, “a”, null, “b”, null<br>
       3. “a”, null, “b”<br>
       4. “a”, “b”<br>
       5. 以上都不对<br>
     * @param param
	 * @param splitToken
	 * @param isIgnoreNull
	 * @return
	 * @exception
	 */
	public static Iterator<String> splitToIterator(String param,String splitToken,boolean isIgnoreNull,int limited){
		Strings.compareNullAndSet(param, "");
		Strings.compareBlankAndSet(splitToken,StringConfig.DEAFAULT_SPLIT_TOKEN);
		Splitter splitter = isIgnoreNull?Splitter.on(splitToken).trimResults().omitEmptyStrings():
							Splitter.on(splitToken).trimResults().limit(limited);
		return splitter.split(param).iterator();
	}
	
	/**  
	 * <b>underLineUpperCaseToLowerCase:下划线操作大写转小写</b>
	 * <p>下划线操作大写转小写：特指带有下划线字符串操作</p>
	 * @return String 转换之后的字符串
	 */ 
	public static String underLineUpperCaseToLowerCase(String param){
		Strings.compareNullAndSet(param, "");
		return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_UNDERSCORE, param);
	}
	
	/**  
	 * <b>underLineLowerCaseToUpperCase:下划线操作小写转大写</b>
	 * <p>下划线操作小写转大写：特指带有下划线字符串操作</p>
	 * @return String 转换之后的字符串
	 */ 
	public static String underLineLowerCaseToUpperCase(String param){
		Strings.compareNullAndSet(param, "");
		return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, param);
	}

	/**
	 * <b>underLineUpperCaseToLowerCamel</b>
	 * <p>大写的下划线字符串转换为小写的驼峰标识字符串
	 * 	一般场景：USER_INFO -> userInfo
	 * 	目的是将数据库表名 转为 java规定的类名称
	 * </p>
	 * @param param
	 * @return
	 * @exception
	 */
	public static String underLineUpperCaseToLowerCamel(String param){
		Strings.compareNullAndSet(param, "");
		return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, param);
	}
	
	/**  
	 * <b>underLineUpperCaseToUpperCamel</b>
	 * <p>大写的下划线字符串转换为大写的驼峰标识字符串
	 * 	一般场景：USER_INFO -> UserInfo 
	 * 	目的是将数据库表名 转为 java规定的类名称
	 * </p>
	 * @param param
	 * @return
	 * @exception
	 */ 
	public static String underLineUpperCaseToUpperCamel(String param){
		Strings.compareNullAndSet(param, "");
		return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, param);
	}
	
	/**  
	 * <b>upperCamelToUnderLineUpperCase</b>
	 * <p>大写的驼峰标识字符串转换为大写的下划线标识字符串
	 * 	一般场景：UserInfo -> USER_INFO 
	 * 	目的是将java规定的类名称->数据库表名
	 * </p>
	 * @param param
	 * @return
	 * @exception
	 */ 
	public static String upperCamelToUnderLineUpperCase(String param){
		Strings.compareNullAndSet(param, "");
		return CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, param);
	}
	
	
	/**  
	 * <b>upperCamelToLowerCamel</b>
	 * <p>大写的驼峰标识字符串转换为小写的驼峰标识字符串
	 * 	一般场景：UserInfo -> USER_INFO 
	 * 	目的是将java规定的类名称->数据库表名
	 */ 
	public static String upperCamelToLowerCamel(String param){
		Strings.compareNullAndSet(param, "");
		return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, param);
	}
	
	/**  
	 * <b>lowerCamelToLowerMLine</b>
	 * <p>小写的驼峰标识字符串转换为小写的中横线标识字符串
	 * 	一般场景：userInfo -> user-info 
	 * 	目的是将java方法名称 转为 一般的变量名称/也可以采用分割得到对象的值
	 * 	比如：set-user-info 可以再次分割 获取set之后的数据信息
	 * </p>
	 * @param param
	 * @return
	 * @exception
	 */ 
	public static String lowerCamelToLowerMLine(String param){
		Strings.compareNullAndSet(param, "");
		return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, param);
	}
	
	/**  
	 * <b>lowerCamelToLowerMLine</b>
	 * <p>小写的驼峰标识字符串转换为大写的中横线标识字符串
	 * 	一般场景：userInfo -> user-info 
	 * 	目的是将java方法名称 转为 一般的变量名称/也可以采用分割得到对象的值
	 * 	比如：set-user-info 可以再次分割 获取set之后的数据信息
	 * </p>
	 * @param param
	 */ 
	public static String lowerCamelToUpperMLine(String param){
		Strings.compareNullAndSet(param, "");
		return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, param).toUpperCase();
	}
	
	public static void main(String[] args) {
		String[] paramArray = new String[]{"123","asda","123d",null};
		System.out.println(join(Arrays.asList(paramArray),"->","&&"));
		System.out.println(join(paramArray,"->","&&"));
		System.out.println(join(Arrays.asList(paramArray).iterator(),"->","&&"));
		System.out.println(splitToList(join(Arrays.asList(paramArray).iterator(),"->","&&"),"->"));
		System.out.println(underLineUpperCaseToUpperCamel("USER_INFO"));
		System.out.println(upperCamelToUnderLineUpperCase("UserInfo"));
		System.out.println(lowerCamelToLowerMLine("UserInfo"));
		System.out.println(lowerCamelToUpperMLine("UserInfo"));
	}
}
